<html>
<head>
  <title>分分钟带你杀入Kaggle Top 1%</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="Evernote Windows/307027 (zh-CN, DDL); Windows/6.1.0 (Win32);"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="529"/>
<h1>分分钟带你杀入Kaggle Top 1%</h1>

<div>
<span><div><h2>0 简介</h2><div>Quora Question Pairs是一个自然语言(NLP)比赛，比赛的题目可以简单地概括为“预测两个问句的语义相似的概率”。其中的样本如下：</div><div style="margin-top: 1em; margin-bottom: 1em;"><br/></div><div><img src="分分钟带你杀入Kaggle Top 1%_files/Image.jpg" type="image/jpeg" data-filename="Image.jpg" width="1955"/></div><div style="margin-top: 1em; margin-bottom: 1em;">也许是作为Kaggle上为数不多的NLP比赛，这看似简单的比赛却吸引了众多的参赛队伍。由于这是NLP问题，所以接下来的介绍都会偏向于NLP，本文会分为以下三个部分：</div><ol><li>打Kaggle比赛的大致套路。（比赛篇）</li><li>我们队伍和其他出色队伍的参赛经验。（经验篇）</li><li>完成Kaggle比赛需要学会哪些实用的工具。（工具篇）</li></ol><div><br/></div><div><br/></div><div><br/></div><h2>1 比赛篇</h2><ol><li><span style="font-weight: bold;">Feature</span> 特征变量，也叫自变量，是样本可以观测到的特征，通常是<span style="font-weight: bold;">模型的输入</span>。</li><li><span style="font-weight: bold;">Label</span> 标签，也叫目标变量，需要预测的变量，通常是<span style="font-weight: bold;">模型的标签或者输出</span>。</li><li><span style="font-weight: bold;">Train Data</span> 训练数据，有标签的数据，由举办方提供。</li><li><span style="font-weight: bold;">Test Data</span> 测试数据，标签未知，是比赛用来评估得分的数据，由举办方提供。</li><li><span style="font-weight: bold;">Train Set</span> 训练集，从Train Data中分割得到的，用于训练模型（常用于交叉验证）。</li><li><span style="font-weight: bold;">Valid Set</span> 验证集，从Train Data中分割得到的，用于验证模型（常用于交叉验证）。</li></ol><div><br/></div><h2><span style="font-weight: normal;">1.1 分析题目</span></h2><div>Kaggle最常见的机器学习问题类型有：</div><ol><li><span style="font-weight: bold;">回归问题</span></li><li><span style="font-weight: bold;">分类问题</span>(二分类、多分类、多标签) 多分类只需从多个类别中预测一个类别，而多标签则需要预测出多个类别。</li></ol><div><br/></div><h2><span style="font-weight: normal;">1.2 数据分析(Data Exploration)</span></h2><div style="margin-top: 1em; margin-bottom: 1em;">所谓数据挖掘，当然是要从数据中去挖掘我们想要的东西，我们需要通过人为地去分析数据，才可以发现数据中存在的问题和特征。我们需要在观察数据的过程中思考以下几个问题：</div><ol><li>数据应该怎么清洗和处理才是合理的？</li><li>根据数据的类型可以挖掘怎样的特征？</li><li>数据中的哪些特征会对标签的预测有帮助？</li></ol><div><br/></div><h2><span style="font-weight: normal;">1.2.1 统计分析</span></h2><div>对于数值类变量（Numerical Variable），我们可以得到min, max, mean, meduim, std 等统计量， 用pandas可以方便地完成，结果如下:</div><div><img src="分分钟带你杀入Kaggle Top 1%_files/Image [1].jpg" type="image/jpeg" data-filename="Image.jpg" style="width: 574.417px; transform: translate3d(31.7917px, 154.342px, 0px) scale3d(1.04106, 1.04106, 1); opacity: 1;"/></div><div><br/></div><div>观察分析：</div><div><ul><li><span style="line-height: 1.45;">该Label是否均衡，不均衡则需要进行over sample少数类，或者down sample多数类。</span></li><li><span style="line-height: 1.45;">统计Numerical Variable之间的相关系数， 用pandas就可以轻松活得相关系数矩阵（观察相关系数矩阵可以让你找到高相关的特征，以及特征之间的冗余度。而对于文本变量，可以统计词频（TF），TF-IDF，文本长度等等。</span></li></ul><div><br/></div></div><div><img src="分分钟带你杀入Kaggle Top 1%_files/Image [2].jpg" type="image/jpeg" data-filename="Image.jpg" width="1600"/></div><div><br/></div><h2><span style="font-weight: normal;">1.2.2 可视化</span></h2><div>比如用直方图展示问句的频数：</div><div><img src="分分钟带你杀入Kaggle Top 1%_files/Image [3].jpg" type="image/jpeg" data-filename="Image.jpg" style="width: 574.417px; transform: translate3d(31.7917px, 145.967px, 0px) scale3d(1.04106, 1.04106, 1); opacity: 1;"/></div><div>绘制相关系数矩阵:</div><div><img src="分分钟带你杀入Kaggle Top 1%_files/Image [4].jpg" type="image/jpeg" data-filename="Image.jpg" width="800"/></div><div><br/></div><div><br/></div><h2>1.3 数据预处理(Data Preprocessing)</h2><div>刚拿到手的数据会出现噪声，缺失，脏乱等现象，我们需要对数据进行清洗与加工，从而方便进行后续的工作。针对不同类型的变量，会有不同的清洗和处理方法：</div><div><ol><li>对于数值型变量（Numerical Variable），需要处理离群点，缺失值，异常值等情况</li><li>对于类别型变量（Categorial Variable），可以转化为one-hot编码</li><li>文本数据是较难处理的数据类型，文本中会有垃圾字符，错别字（词），数学公式，不统一单位和日期格式等。我们还需要处理标点符号，分词，去停用词，对于英文文本可能还要词性还原(lemmatize)，抽取词干(stem)等等。</li></ol><div><br/></div></div><div><br/></div><h2>1.4 特征工程(Feature Engineering)</h2><div><span style="font-weight: bold;">都说特征为王，特征是决定效果最关键的一环。</span>我们需要通过探索数据，<font style="font-size: 14pt;"><span style="color: rgb(227, 0, 0); font-size: 14pt; font-weight: bold;">利用人为先验知识</span></font>，从数据中总结出特征。</div><div><br/></div><h2><span style="font-weight: normal;">1.4.1 特征抽取(Feature Extraction)</span></h2><div><span style="font-weight: bold;">我们应该尽可能多地抽取特征，只要你认为某个特征对解决问题有帮助，它就可以成为一个特征。</span>特征抽取需要不断迭代，是最为烧脑的环节，它会在整个比赛周期折磨你，但这是比赛取胜的关键，它值得你耗费大量的时间。</div><div>新手，可以先耗费一些时间在Forum上，看看别人是怎么做Feature Extraction的，并且多思考。虽然Feature Extraction特别讲究经验，但其实还是有章可循的：</div><div><ol><li>对于Numerical Variable， 可以通过线性组合、多项式组合来发现新的Feature</li><li>对于文本数据，有一些常规的Feature。比如，书本长度，Embeddings,TF-IDF， LDA， LSI 等，甚至可以用深度学习提取文本特征（隐藏层）</li><li>如果你想对数据有更深入的了解，可以通过思考数据集的构造过程来发现一些magic feature，这些特征有可能会大大提升效果。在Quora这次比赛中，就有人公布了一些magic feature。</li><li>通过<span style="font-weight: bold;">错误分析</span>也可以发现新的特征（见1.5.2小节）。</li></ol><div><br/></div></div><div><br/></div><h2><span style="font-weight: normal;">1.4.2 特征选择(Feature Selection)</span></h2><div>在做特征抽取的时候，我们是尽可能地抽取更多的Feature，但过多的Feature会造成冗余，噪声，容易过拟合等问题，因此我们需要进行特征筛选。特征选择可以加快模型的训练速度，甚至还可以提升效果。</div><div>特征选择的方法多种多样，最简单的是相关度系数(Correlation coefficient)，它主要是衡量两个变量之间的线性关系，数值在[-1.0, 1.0]区间中。<span style="font-weight: bold;">数值越是接近0，两个变量越是线性不相关。但是数值为0，并不能说明两个变量不相关，只是线性不相关而已。</span></div><div><br/></div><div>怎么分析相关系数矩阵：</div><div><img src="分分钟带你杀入Kaggle Top 1%_files/Image [5].jpg" type="image/jpeg" data-filename="Image.jpg" width="800"/></div><ol><li><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">Feature和Label的相关度可以看作是该Feature的重要度，越接近1或-1就越好。</span></font></li><li><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">Feature和Feature之间的相关度要低，如果两个Feature的相关度很高，就有可能存在冗余。</span></font></li></ol><div><br/></div><div>除此之外，还可以训练模型来筛选特征，比如带L1或L2惩罚项的Linear Model、Random Forest、GDBT等，它们都可以输出特征的重要度。在这次比赛中，我们对上述方法都进行了尝试，将不同方法的平均重要度作为最终参考指标，筛选掉得分低的特征。</div><div><br/></div><div><br/></div><h2>1.5 建模(Modeling)</h2><h2><span style="font-weight: normal;">1.5.1 模型</span></h2><div style="margin-top: 1em; margin-bottom: 1em;">机器学习模型有很多，建议均作尝试，不仅可以测试效果，还可以学习各种模型的使用技巧。其实，几乎每一种模型都有回归和分类两种版本，常用模型有：</div><ul><li><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">KNN</span></font></li><li><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">SVM</span></font></li><li><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">Linear Model（带惩罚项）</span></font></li><li><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">ExtraTree</span></font></li><li><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">RandomForest</span></font></li><li><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">Gradient Boost Tree</span></font></li><li><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">Neural Network</span></font></li></ul><div>幸运的是，这些模型都已经有现成的工具（如scikit-learn、XGBoost、LightGBM等）可以使用，不用自己重复造轮子。但是我们应该要知道各个模型的原理，这样在调参的时候才会游刃有余。当然，你也使用PyTorch／Tensorflow／Keras等深度学习工具来定制自己的Deep Learning模型，玩出自己的花样。</div><div><br/></div><h2><span style="font-weight: normal;">1.5.2 错误分析</span></h2><div><span style="font-weight: bold;">人无完人，每个模型不可能都是完美的，它总会犯一些错误</span>。为了解某个模型在犯什么错误，我们可以观察被模型误判的样本，总结它们的共同特征，我们就可以再训练一个效果更好的模型。这种做法有点像后面Ensemble时提到的Boosting，但是我们是人为地观察错误样本，而Boosting是交给了机器。通过<span style="font-weight: bold;">错误分析-&gt;发现新特征-&gt;训练新模型-&gt;错误分析</span>，可以不断地迭代出更好的效果，并且这种方式还可以培养我们对数据的嗅觉。</div><div><br/></div><div>举个例子，这次比赛中，我们在错误分析时发现，某些样本的两个问句表面上很相似，但是句子最后提到的地点不一样，所以其实它们是语义不相似的，但我们的模型却把它误判为相似的。比如这个样本：</div><ul><li>Question1: Which is the best digital marketing institution in banglore?</li><li>Question2: Which is the best digital marketing institute in Pune?</li></ul><div>为了让模型可以处理这种样本，我们将两个问句的最长公共子串(Longest Common Sequence)去掉，用剩余部分训练一个新的深度学习模型，相当于告诉模型看到这种情况的时候就不要判断为相似的了。因此，在加入这个特征后，我们的效果得到了一些提升。</div><div><br/></div><div><br/></div><h2><span style="font-weight: normal;">1.5.3 调参</span></h2><div style="margin-top: 1em; margin-bottom: 1em;">在训练模型前，我们需要预设一些参数来确定<span style="font-weight: bold;">模型结构</span>（比如树的深度）和<span style="font-weight: bold;">优化过程</span>（比如学习率），这种参数被称为<span style="font-weight: bold;">超参（Hyper-parameter）</span>，不同的参数会得到的模型效果也会不同。总是说调参就像是在“炼丹”，像一门“玄学”，但是根据经验，还是可以找到一些章法的：</div><ol><li>根据经验，选出对模型效果<span style="font-weight: bold;">影响较大的超参</span>。</li><li>按照经验设置超参的<span style="font-weight: bold;">搜索空间</span>，比如学习率的搜索空间为[0.001，0.1]。</li><li>选择<span style="font-weight: bold;">搜索算法</span>，比如Random Search、Grid Search和一些启发式搜索的方法。</li><li><span style="font-weight: bold;">验证模型</span>的泛化能力（详见下一小节）。</li></ol><div><br/></div><h2><span style="font-weight: normal;">1.5.4 模型验证(Validation)</span></h2><div>在Test Data的标签未知的情况下，我们需要自己构造测试数据来验证模型的泛化能力，因此把Train Data分割成Train Set和Valid Set两部分，Train Set用于训练，Valid Set用于验证。</div><div><br/></div><ul><li><span style="font-weight: bold;">简单分割</span></li></ul><div style="margin-top: 1em; margin-bottom: 1em;">将Train Data按一定方法分成两份，比如随机取其中70%的数据作为Train Set，剩下30%作为Valid Set，每次都固定地用这两份数据分别训练模型和验证模型。这种做法的缺点很明显，它没有用到整个训练数据，所以验证效果会有偏差。通常只会在训练数据很多，模型训练速度较慢的时候使用。</div><ul><li><span style="font-weight: bold;">交叉验证</span></li></ul><div style="margin-top: 1em; margin-bottom: 1em;">交叉验证是将整个训练数据随机分成K份，训练K个模型，每次取其中的K-1份作为Train Set，留出1份作为Valid Set，因此也叫做<span style="font-weight: bold;">K-fold</span>。至于这个K，你想取多少都可以，但一般选在3～10之间。我们可以用K个模型得分的mean和std，来评判模型得好坏（mean体现模型的能力，std体现模型是否容易过拟合），并且用K-fold的验证结果通常会比较可靠。</div><div>如果数据出现Label不均衡情况，可以使用Stratified K-fold，这样得到的Train Set和Test Set的Label比例是大致相同。</div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><h2>1.6 模型集成(Ensemble)</h2><div>曾经听过一句话，<span style="font-weight: bold;">”Feature为主，Ensemble为后”</span>。Feature决定了模型效果的上限，而Ensemble就是让你更接近这个上限。Ensemble讲究“好而不同”，不同是指模型的学习到的侧重面不一样。举个直观的例子，比如数学考试，A的函数题做的比B好，B的几何题做的比A好，那么他们合作完成的分数通常比他们各自单独完成的要高。</div><div>常见的Ensemble方法有Bagging、Boosting、Stacking、Blending。</div><div><br/></div><h2><span style="font-weight: normal;">1.6.1 Bagging</span></h2><div>Bagging是将多个模型（<span style="font-weight: bold;">基学习器</span>）的预测结果简单地<span style="font-weight: bold;">加权平均或者投票</span>。Bagging的好处在于可以并行地训练基学习器，其中Random Forest就用到了Bagging的思想。</div><div>Bagging通常是没有一个明确的优化目标的，但是有一种叫<a href="http://link.zhihu.com/?target=http%3A//www.cs.cornell.edu/%7Ealexn/papers/shotgun.icml04.revised.rev2.pdf">Bagging Ensemble Selection</a>的方法，它通过贪婪算法来Bagging多个模型来优化目标值</div><div><br/></div><h2><span style="font-weight: normal;">1.6.2 Boosting</span></h2><div>Boosting的思想有点像<span style="font-weight: bold;">知错能改</span>，每训练一个基学习器，是为了弥补上一个基学习器所犯的错误。其中著名的算法有AdaBoost，Gradient Boost。Gradient Boost Tree就用到了这种思想。</div><div>我在1.2.3节(错误分析)中提到Boosting，错误分析-&gt;抽取特征-&gt;训练模型-&gt;错误分析，这个过程就跟Boosting很相似。</div><div><br/></div><div><br/></div><h2><span style="font-weight: normal;">1.6.3 Stacking</span></h2><div>Stacking是用新的模型（<span style="font-weight: bold;">次学习器</span>）去<span style="font-weight: bold;">学习怎么组合</span>那些<span style="font-weight: bold;">基学习器</span>，它的思想源自于<a href="http://link.zhihu.com/?target=http%3A//www.machine-learning.martinsewell.com/ensembles/stacking/Wolpert1992.pdf">Stacked Generalization</a>这篇论文。如果把Bagging看作是多个基分类器的线性组合，那么Stacking就是多个基分类器的非线性组合。Stacking可以很灵活，它可以将学习器一层一层地堆砌起来，形成一个网状的结构，如下图：</div><div><img src="分分钟带你杀入Kaggle Top 1%_files/Image [6].jpg" type="image/jpeg" data-filename="Image.jpg" width="800"/></div><div><br/></div><h2><span style="font-weight: normal;">1.6.4 Blending</span></h2><div>Blending与Stacking很类似，它们的区别可以参考<a href="http://link.zhihu.com/?target=https%3A//mlwave.com/kaggle-ensembling-guide/">这里</a></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><h2>2 经验篇</h2><h2>2.1 我们的方案（33th）</h2><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div></div></span>
</div></body></html> 